package com.ndp.fb.walle.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.ndp.fb.enums.ErrorType;
import com.ndp.fb.enums.adgroupstatus.AdGroupStatus;
import com.ndp.fb.enums.adsetstatus.AdSetStatus;
import com.ndp.fb.rdb.model.Pager;
import com.ndp.fb.rdb.model.User;
import com.ndp.fb.rulescript.api.OptimizationLogQuery;
import com.ndp.fb.rulescript.api.RuleResultQuery;
import com.ndp.fb.rulescript.model.AdSetResult;
import com.ndp.fb.rulescript.model.OptLogBo;
import com.ndp.fb.rulescript.model.OptRecordBo;
import com.ndp.fb.util.ListUtil;
import com.ndp.fb.walle.business.RuleResultService;
import com.ndp.fb.walle.model.vo.OutputResult;
import com.ndp.fb.walle.model.vo.PageResult;
import com.ndp.fb.walle.model.vo.ruleresult.param.OptLogPageParam;
import com.ndp.fb.walle.model.vo.ruleresult.param.RuleExeAdGroupVo;
import com.ndp.fb.walle.model.vo.ruleresult.param.RuleExecuteVoParam;
import com.ndp.fb.walle.model.vo.ruleresult.param.RuleResultQueryParamVo;
import com.ndp.fb.walle.util.ResponseUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by hunk.qin on 2015/7/13.
 */
@RequestMapping("/ruleresult")
@Controller
public class RuleResultController {

    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

    @Reference
    private RuleResultQuery ruleResultQuery;

    @Autowired
    private RuleResultService ruleResultService;

    @Reference
    private OptimizationLogQuery optimizationLogQuery;


    /**
     * 获取 规则优化后的分组结果
     *
     * @return
     */
    @RequestMapping(value = "grouplist")
    @ResponseBody
    public ResponseEntity<String> groupList(@RequestParam(value = "param", required = true) String param,HttpSession session) {
        logger.info("group list begin.");
        ErrorType errorType = null;
        List<String> grouplist = null;
        try {
            User user = (User) session.getAttribute("user");
            RuleResultQueryParamVo paramVo = JSON.parseObject(param, RuleResultQueryParamVo.class);
            grouplist = ruleResultQuery.queryGroupList(user.getTicket(),paramVo.getIswatch());
        } catch (Exception e) {
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage(), e);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, grouplist);
        logger.info("group list end.");
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }


    /**
     * 获取 一个分组下面未优化的广告记录
     *
     * @param param   分组标示
     * @param session
     * @return
     */
    @RequestMapping(value = "ruleResultList")
    @ResponseBody
    public ResponseEntity<String> ruleResultList(@RequestParam(value = "param", required = true) String param, HttpSession session) {
        logger.info("ruleResultList list begin.");
        ErrorType errorType = null;
        Map<String, Object> data = null;
        try {
            User user = (User) session.getAttribute("user");
            RuleResultQueryParamVo paramVo = JSON.parseObject(param, RuleResultQueryParamVo.class);
            Pager<AdSetResult> adSetResultPager = ruleResultQuery.queryAdsetList(paramVo.getCPage() - 1, paramVo.getPSize(),
                    user.getTicket(), paramVo.getFbConnectionObjectId(), paramVo.getPlatform(),
                    paramVo.getGroup(), paramVo.getIswatch(),paramVo.getFbAccountIds(),paramVo.getSortMix(),paramVo.getSortMax());
            long tSize = adSetResultPager.getTotalSize();
            float nrOfPages = (float) tSize / paramVo.getPSize();
            int tPage = (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages);
            PageResult pageResult = new PageResult(tPage, paramVo.getCPage(), paramVo.getPSize(), tSize);

            // 封装响应结果
            data = new HashMap<>();
            data.put("ruleresult", adSetResultPager.getResultList());
            data.put("paginator", pageResult);
        } catch (Exception e) {
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage(), e);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, data);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 执行优化操作
     *
     * @param param
     * @return
     */
    @RequestMapping(value = "exeOptimize")
    @ResponseBody
    public ResponseEntity<String> exeOptimize(@RequestParam(value = "param", required = true) String param,HttpServletRequest request) {
        ErrorType errorType = null;
        Map<String, Object> data = null;
        User user= (User) request.getSession().getAttribute("user");
        //优化日志对象
        OptLogBo optLog=new OptLogBo();
        List<OptRecordBo> records=new ArrayList<>();
        optLog.setUserId(user.getTicket());
        optLog.setRecords(records);
        try {
            RuleExecuteVoParam opt = JSON.parseObject(param, RuleExecuteVoParam.class);
            optLog.setRuleScriptId(opt.getRuleId());
            optLog.setWatchType(opt.getIsWatch());
            optLog.setAdSetId(opt.getAdSetId());
            Integer watchDelay=0;
            if (opt.getIsWatch()==1) {
                watchDelay=opt.getDelayHours();
            }else if(opt.getIsWatch()==2) {
                watchDelay=opt.getDelaySpent();
            }
            optLog.setWatchDelay(watchDelay);
            data = new HashMap<>();
            Long adSetId = opt.getAdSetId();
            if (adSetId == null) {
                data.put("error", "invalid param");
                throw new Exception("invalid param,adSetId must not be null.");
            } else {
                logger.info("优化广告系列{}", adSetId);
            }
            if (opt.getBudgetNew() != null && opt.getBudgetType() != null) {
                //改预算
            } else if (opt.getStatus() != null) {
                //修改状态
                if (AdSetStatus.getStatus(opt.getStatus()) == null) {
                    logger.error("adSet状态不正确，必须是以下的其中一个: ACTIVE,PAUSED,ARCHIVED,DELETED!");
                    throw new Exception("adSet状态不正确，必须是以下的其中一个: ACTIVE,PAUSED,ARCHIVED,DELETED!");
                }
            }
            List<OptRecordBo> adSetRecords = ruleResultService.updateAdSet(opt,user.getTicket());
            records.addAll(adSetRecords);
            //修改ad
            if (!CollectionUtils.isEmpty(opt.getAds())) {
                for (RuleExeAdGroupVo ad : opt.getAds()) {
                    if (AdGroupStatus.getStatus(ad.getStatus()) == null) {
                        logger.error("adGroupId:{},状态参数不正确，必须是以下中的一个:ACTIVE,PAUSED,ARCHIVED,DELETED!",ad.getAdGroupId());
                        throw new Exception("adGroupId:"+ad.getAdGroupId()+"，状态参数不正确，必须是以下中的一个:ACTIVE,PAUSED,ARCHIVED,DELETED!");
                    }
                    OptRecordBo optRecordBo = ruleResultService.updateAdGroup(ad.getAdGroupId(), ad.getStatus(), opt,user.getTicket());
                    records.add(optRecordBo);
                }
            }
            if (opt.getIsWatch().intValue() == 0) {
                //0，不需要观察，花费和时间都置为空
                opt.setDelaySpent(null);
                opt.setDelayHours(null);
            } else if (opt.getIsWatch().intValue() == 1) {
                //1:按时间观察，花费置空
                opt.setDelaySpent(null);
            } else if (opt.getIsWatch().intValue() == 2) {
                //2:按花费观察，时间置空
                opt.setDelayHours(null);
            } else {
                logger.error("adSetId:{},是否观察参数错误，必须是0，1，2其中一个。",opt.getAdSetId());
                throw new Exception("adSetId:"+opt.getAdSetId()+",是否观察参数错误，必须是0，1，2其中一个。");
            }
            ruleResultService.updateRuleResult(optLog);
            data.put("ok", "ok");
        } catch (Exception e) {
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage(), e);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, data);
        logger.info("ruleResultList list end.");
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 优化记录
     * @param param
     * @param session
     * @return
     */
    @RequestMapping(value = "getOptLogs")
    public ResponseEntity<String>  getOptLogs(@RequestParam(value = "param", required = true)String param, HttpSession session) {
        ErrorType errorType = null;
        User user = (User) session.getAttribute("user");
        List<OptLogBo> optLogs = null;
        Map data = new HashMap<String, Object>();
        try {
            OptLogPageParam pageParam = JSON.parseObject(param, OptLogPageParam.class);
            //后端以0开始
            Pager pager = optimizationLogQuery.findByUserId(user.getTicket(), pageParam.getCPage() -1 , pageParam.getPSize());
            optLogs= pager.getResultList();
            if (ListUtil.isNotEmpty(optLogs)) {
                buildLogDesc(optLogs);
            }
            PageResult pageResult=new PageResult();
            pageResult.setCPage(pageParam.getCPage());
            pageResult.setPSize(pageParam.getPSize());
            pageResult.setTSize(pager.getTotalSize());
            pageResult.setTPage((int) (pager.getTotalSize()/pageParam.getPSize()+1));
            data.put("logs", optLogs);
            data.put("paginator", pageResult);
        } catch (Exception e) {
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage());
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, data);
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    private void buildLogDesc(List<OptLogBo> optLogs) {
        List<OptRecordBo> records;
        for (OptLogBo optLog : optLogs) {
            StringBuffer desc = new StringBuffer();
            records = optLog.getRecords();
            if (!records.isEmpty()){
                for (OptRecordBo record : records) {
                    if ("dailyBudget".equals(record.getOptType())) {
                        desc.append(",将日预算从$" + Double.valueOf(record.getBefore())/100 + "调整为$" + Double.valueOf(record.getAfter())/100);
                    } else if ("lifetimeBudget".equals(record.getOptType())) {
                        desc.append("$，将总预算从" + Double.valueOf(record.getBefore())/100 + "调整为$" + Double.valueOf(record.getAfter())/100);
                    } else if ("status".equals(record.getOptType()) && record.getAdSetId() != null) {
                        desc.append("，将广告系列状态从" + record.getBefore() + "调整为" + record.getAfter());
                    } else if ("status".equals(record.getOptType()) && record.getAdGroupId() != null) {
                        desc.append("，将广告"+record.getAdGroupId()+"从" + record.getBefore() + "调整为" + record.getAfter());
                    } else if ("price".equals(record.getOptType()) && record.getAdSetId() != null) {
                        desc.append("，将出价从$" + Double.valueOf(record.getBefore())/100 + "调整为$" + Double.valueOf(record.getAfter())/100);
                    }
                }
            }
            if (optLog.getWatchType()==0) {
                if (desc.length()>0) {
                    desc.append("，不观察");
                }else {
                    desc.append("，取消观察");
                }
            }else if(optLog.getWatchType()==1){
                desc.append("，观察"+optLog.getWatchDelay()+"H");
            }else if(optLog.getWatchType()==2){
                desc.append("，观察"+optLog.getWatchDelay()+"$");
            }
            desc.append("。");
            optLog.setDesc(desc.toString().substring(1));
        }
    }

    /**
     * 清除快照
     * @param session
     * @return
     */
    @RequestMapping(value = "cleanAllSnap")
    @ResponseBody
    public ResponseEntity<String> cleanAllSnap(HttpSession session) {
        logger.info("rulescript cleanAllSnap begin.");
        ErrorType errorType = null;
        User user = (User) session.getAttribute("user");
        try {
            ruleResultQuery.cleanResultByUserId(user.getTicket());
        } catch (Exception e){
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage(), e);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, null);
        logger.info("rulescript cleanAllSnap end.");
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }

    /**
     * 获取指定Adset的建议出价信息
     * @param param
     * @return
     */
    @RequestMapping(value = "queryOfferBid")
    @ResponseBody
    public ResponseEntity<String> queryOfferBid(@RequestParam(value = "param", required = true) String param) {
        logger.info("rulescript queryOfferBid begin.");
        Map<String, Object> data = null;
        ErrorType errorType = null;
        try {
            RuleExecuteVoParam opt = JSON.parseObject(param, RuleExecuteVoParam.class);
            String offerBid = ruleResultQuery.queryAdsetOfferBid(opt.getAdSetId());
            data = new HashMap<>();
            data.put("offerbid", offerBid);
        } catch (Exception e){
            errorType = ErrorType.INTERNAL_EXCEPTION;
            logger.error(e.getMessage(), e);
        }
        OutputResult outputResult = ResponseUtils.bulidOutputResult(errorType, data);
        logger.info("rulescript queryOfferBid end.");
        return ResponseUtils.returnJsonWithUTF8(JSON.toJSONString(outputResult));
    }
}
